package net.sudot.chess.plugin.payment.codepay;

import net.sudot.chess.business.model.PaymentTransaction;
import net.sudot.chess.business.model.PluginConfig;
import net.sudot.chess.plugin.PluginAttributeConfig;
import net.sudot.chess.plugin.payment.PaymentPlugin;
import net.sudot.commons.json.JsonUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

/**
 * 码支付
 *
 * @author tangjialin on 2018-03-18.
 * @see <a href="https://codepay.fateqq.com/">https://codepay.fateqq.com/</a>
 */
public abstract class CodePaymentPlugin extends PaymentPlugin {
    private Logger logger = LoggerFactory.getLogger(getClass());
    /** 扩展属性配置 */
    private List<PluginAttributeConfig> attributeConfigs = new ArrayList<>();

    {
        attributeConfigs.add(new PluginAttributeConfig("appId", "码支付ID", true));
        attributeConfigs.add(new PluginAttributeConfig("appSecret", "通信密钥", true));
        attributeConfigs.add(new PluginAttributeConfig("token", "Token", true));
        attributeConfigs.add(new PluginAttributeConfig(PaymentPlugin.LOGO_ATTRIBUTE_NAME, "LOGO"));
        attributeConfigs.add(new PluginAttributeConfig(PaymentPlugin.DESCRIPTION_ATTRIBUTE_NAME, "描述"));
    }

    @Override
    public String getName() {
        return "码支付";
    }

    @Override
    public List<PluginAttributeConfig> getAttributeConfigs() {
        return attributeConfigs;
    }

    @Override
    public boolean supports(HttpServletRequest request) {
        return true;
    }

    @Override
    public String payHandle(PaymentTransaction paymentTransaction, String paymentDescription, String extra, HttpServletRequest request, HttpServletResponse response) {
        String paymentSn = paymentTransaction.getSn();
        TreeMap<String, Object> parameterMap = new TreeMap<>();
        parameterMap.put("id", getAppId());
        parameterMap.put("pay_id", paymentSn);
        // 金额调用toString,否则签名中生成的金额和页面中不一致,导致前面错误
        parameterMap.put("price", paymentTransaction.getAmount().toString());
        // 自定义参数,会原样通过param参数返回
        parameterMap.put("param", "");
        // 支付类型  1：支付宝 2：QQ钱包 3：微信
        parameterMap.put("type", getType().getValue());
        parameterMap.put("return_url", getPayAfterUrl(paymentSn, extra));
        parameterMap.put("notify_url", getPayAfterUrl(paymentSn, "notify"));
        parameterMap.put("sign", generateSign(parameterMap));
        // 添加参数到页面
        request.setAttribute("parameterMap", parameterMap);
        request.setAttribute("requestUrl", "https://codepay.fateqq.com:51888/creat_order");
        return super.payHandle(paymentTransaction, paymentDescription, extra, request, response);
        // 下面这种方式也可以,只不过是GET请求,参数都暴露在浏览器地址栏中了
//        return "redirect:" + CREAT_ORDER_URL + joinKeyValue(parameterMap, "?", "&sign=" + sign, "&", true);
    }

    @Override
    public String payAfterHandle(PaymentTransaction paymentTransaction, String paymentDescription, String extra, boolean isPaySuccess, HttpServletRequest request, HttpServletResponse response) {
        if ("notify".equals(extra)) {
            request.setAttribute("message", "success");
        }
        return super.payAfterHandle(paymentTransaction, paymentDescription, extra, isPaySuccess, request, response);
    }

    @Override
    public boolean isPaySuccess(PaymentTransaction paymentTransaction, String paymentDescription, String extra, HttpServletRequest request, HttpServletResponse response) {
        // 获取请求的全部参数
        TreeMap<String, Object> requestParams = new TreeMap<>(request.getParameterMap());
        logger.info("收到[{}]支付通知结果:{}", getName(), JsonUtils.toJson(requestParams));
        String sign = generateSign(requestParams);
        if (sign.equals(requestParams.get("sign"))) {
            /**
             * {
             *     "codepay_server_time": "1524494125",
             *     "endTime": "1524490544",
             *     "id": "33275429",
             *     "mode": "0",
             *     "param": "",
             *     "pay_id": "96358283451039744",
             *     "pay_no": "1000050301180423021202000031071188436913",
             *     "pay_time": "1524490528",
             *     "money": "0.02", // 客户实际支付的金额
             *     "price": "0.01", // 提交的订单金额
             *     "sign": "b074af4100ddc9b0988fc376c8b93b8e",
             *     "status": "1",
             *     "tag": "0",
             *     "trade_no": "115244904153438319711614700",
             *     "trueID": "43831",
             *     "type": "3",
             *     "userID": "43831"
             * }
             * sign=6acb56bda5f63d04c30515f4c5918b23&codepay_server_time=1524494168&endTime=1524490544&id=33275429&mode=0&money=0.02&param=96358283451039744&pay_id=96358283451039744&pay_no=1000050301180423021202000031071188436913&pay_time=1524490528&price=0.01&status=1&tag=0&trade_no=115244904153438319711614700&trueID=43831&type=3&userID=43831
             */
            String payNo = request.getParameter("pay_no"); // 流水号
            String payId = request.getParameter("pay_id"); // 用户唯一标识
            if (paymentTransaction.getSn().equals(payId)) {
                // 记录流水号
                paymentTransaction.setExtSn(payNo);
                paymentTransaction.setAmount(new BigDecimal(request.getParameter("money")));
                return true;
            }
        }
        return false;
    }

    /**
     * 获取AppID
     *
     * @return AppID
     */
    protected String getAppId() {
        PluginConfig pluginConfig = getConfig();
        return pluginConfig.getAttribute("appId");
    }

    /**
     * 获取Token
     *
     * @return Token
     */
    protected String getToken() {
        PluginConfig pluginConfig = getConfig();
        return pluginConfig.getAttribute("token");
    }

    /**
     * 获取AppSecret
     *
     * @return AppSecret
     */
    protected String getAppSecret() {
        PluginConfig pluginConfig = getConfig();
        return pluginConfig.getAttribute("appSecret");
    }

    /**
     * 生成签名
     *
     * @param parameterMap 参数
     * @return 签名
     */
    protected String generateSign(TreeMap<String, Object> parameterMap) {
        return DigestUtils.md5Hex(joinKeyValue(parameterMap, null, null, "&", true, "sign") + getAppSecret());
    }

    /**
     * 获取支付类型
     *
     * @return 返回支付类型
     */
    public abstract Type getType();

    /**
     * 支付类型
     */
    protected enum Type {
        ALIPAY(1, "支付宝"),
        QQ(2, "QQ钱包"),
        WECHAT(3, "微信");
        private int value;
        private String remark;

        private Type(int value, String remark) {
            this.value = value;
            this.remark = remark;
        }

        public int getValue() {
            return value;
        }

        public String getRemark() {
            return remark;
        }
    }
}